﻿using System.Collections;
using ArmyAnt.ProcessController;
using Newtonsoft.Json;
using PlayMyLife.Definitions.HumanProperty;
using PlayMyLife.Definitions.StoryEvent;
using PlayMyLife.Events;
using PlayMyLife.ModelInterface;
using PlayMyLife.ModelLocal;

namespace PlayMyLife.Present {
    public interface IOperaDataReader {
        public IConfigManager ConfigManager { get; }
        public IRolesReader RolesReader { get; }
        public IPlaceReader PlaceReader { get; }
    }

    public class OperaDirector : IOperaDataReader {
        public const long SELF_PLAYER_ID = 1;

        public IEventManager<DirectorEvent> EventMgr { get; private set; }
        public ICoroutineExecuter CoroutineExecuter { get; private set; }

        public IConfigManager ConfigManager { get; private set; }
        public ILeadingRole LeadingRole { get; private set; }
        public IRolesManager RolesManager { get; private set; }
        public IRolesReader RolesReader => RolesManager;
        public IPlaceManager PlaceManager { get; private set; }
        public IPlaceReader PlaceReader => PlaceManager;

        public long CurrentEventId { get; private set; }
        public EventType CurrentEventType { get; private set; }

        public OperaDirector(IEventManager<DirectorEvent> eventMgr, ICoroutineExecuter coroutineExecuter, string eventConfig, string skillConfig) {
            EventMgr = eventMgr;
            EventMgr.Listen(DirectorEvent.LoadGame, OnLoadGame);
            EventMgr.Listen(DirectorEvent.PlaceOperate, OnPlaceOperate);
            EventMgr.Listen(DirectorEvent.ConversationStepOn, OnConversationStepOn);
            EventMgr.Listen(DirectorEvent.ChoiceStepOn, OnChoiceStepOn);

            CoroutineExecuter = coroutineExecuter;

            var localConfigManager = new LocalConfigManager();
            localConfigManager.InitFromText(eventConfig, skillConfig);
            ConfigManager = localConfigManager;
            LeadingRole = new LocalLeadingRole();
            RolesManager = new LocalRolesManager();
            PlaceManager = new LocalPlaceManager();

            EventMgr.NotifyAsync(new EventArgs_ShowPanel(PanelType.StartPanel, PanelLayer.FullScreen));
        }

        ~OperaDirector() {
            EventMgr.Unlisten(DirectorEvent.LoadGame, OnLoadGame);
            EventMgr.Unlisten(DirectorEvent.ConversationStepOn, OnConversationStepOn);
        }

        private void OnLoadGame(IEventManager<DirectorEvent>.IEventArgs e) {
            if(e is EventArgs_LoadGame arg) {
                InitNewOpera(arg.Name, arg.Gender, arg.BirthMonth, arg.BirthDay, arg.Mbti, 0);
                EventMgr.NotifyAsync(new EventArgs_ShowPanel_WithDirectorReader(this));
            }
        }

        public void InitNewOpera(Name name, GenderType gender, int birthMonth, int birthDay, MbtiType mbti, int index) {
            LeadingRole.LeadingRoleData.id = SELF_PLAYER_ID;

            LeadingRole.LeadingRoleData.baseProperty = new() {
                name = name,
                gender = gender,
                birthMonth = birthMonth,
                birthDay = birthDay,
                mbti = mbti,
                beautyCharmValue = 750,
                sociatyCharmValue = 650,
                intelligent = 900,
            };

            LeadingRole.LeadingRoleData.status = new() {
                energy = 1000,
                health = 1000,
                physics = 1000,

                immunity = 1000,
                endurance = 1000,
                power = 1000,
                runningSpeed = 1000,
                bodySensitivity = 1000,
                fingersSensitivity = 1000,

                embarassed = 1000,
                happiness = 1000,
                fear = 1000,
                anger = 1000,
                shyness = 1000,

                happinessSensitivity = 1000,
                fearSensitivity = 1000,
                angerSensitivity = 1000,
                shynessSensitivity = 1000,
                bravery = 1000,
                rational = 1000,
                decisiveness = 1000,

                hygiene = 1000,
                hygieneSelfThresold = 1000,
                hygieneOthersThresold = 1000,

                sociatyExp = 1000,
                sociatyFame = 1000,
                sociatyEvaluate = 1000,
            };

            ResolveEvent(gender == GenderType.Female ? 1001 : 1002);
        }

        private void ResolveEvent(long eventId) {
            var cfg = ConfigManager.GetEventByID(eventId);
            CurrentEventId = cfg.id;
            CurrentEventType = cfg.eventType;
            CoroutineExecuter.RunCoroutine(ResolveBaseEvent(CurrentEventType, 0, cfg.argsID));
            foreach(var i in cfg.withinEvents) {
                CoroutineExecuter.RunCoroutine(ResolveBaseEvent(i.eventType, i.eventDelay, i.argsID));
            }
        }

        private IEnumerator ResolveBaseEvent(EventType eventType, long eventDelay, string argsID) {
            var tarArgs = ConfigManager.EventConfig.args[argsID];
            if(eventDelay > 0) {
                yield return CoroutineExecuter.CreateSecondsDelay(eventDelay / 1000f);
            }
            switch(eventType) {
                case EventType.NothingDelay:
                    break;
                case EventType.EnableOperate:
                    OnEnableOperate(tarArgs);
                    break;
                case EventType.Conversation:
                    OnConversation(tarArgs);
                    break;
                case EventType.Choices:
                    OnChoices(tarArgs);
                    break;
                case EventType.PlaceMove:
                    OnPlaceMove(tarArgs);
                    break;
                case EventType.SpecialResolve:
                    break;
                case EventType.GotItem:
                    break;
                case EventType.CreatePlace:
                    OnCreatePlace(tarArgs);
                    break;
                case EventType.CreateItem:
                    break;
                case EventType.CreateRole:
                    OnCreateRole(tarArgs);
                    break;
                case EventType.PlaceChange:
                    break;
                case EventType.ItemChange:
                    break;
                case EventType.RoleChange:
                    break;
                case EventType.RelationChange:
                    break;
                case EventType.BgmPlay:
                    break;
                case EventType.SoundPlay:
                    break;
            }
        }

        private void OnEnableOperate(string argStr) {
            var arg = JsonConvert.DeserializeObject<EnableOperateEventArg>(argStr);
            EventMgr.NotifyAsync(new EventArgs_EnableOperate(arg.enable));
        }

        private void OnConversation(string argStr) {
            var arg = JsonConvert.DeserializeObject<ConversationEventArg>(argStr);
            EventMgr.NotifyAsync(new EventArgs_ShowConversation(arg.speaker, arg.content, arg.nextEventId));
        }

        private void OnChoices(string argStr) {
            var arg = JsonConvert.DeserializeObject<ChoicesEventArg>(argStr);
            EventMgr.NotifyAsync(new EventArgs_ShowChoices(arg.title, arg.texts, arg.events));
        }

        private void OnPlaceMove(string argStr) {
            var arg = JsonConvert.DeserializeObject<PlaceMoveEventArg>(argStr);
            PlaceManager.MoveTo(arg.placeId, arg.roleId);
            if(arg.roleId == SELF_PLAYER_ID) {
                EventMgr.NotifyAsync(new EventArgs_ShowPlace(arg.placeId));
            }
        }

        private void OnCreatePlace(string argStr) {
            var arg = JsonConvert.DeserializeObject<CreatePlaceEventArg>(argStr);
            PlaceManager.AddPlaceData(arg);
        }

        private void OnCreateRole(string argStr) {
            var arg = JsonConvert.DeserializeObject<CreateRoleEventArg>(argStr);
            RolesManager.AddRoleData(arg);
            foreach(var i in arg.relations) {
                RolesManager.ChangeRelation(i);
            }
        }

        private void OnPlaceOperate(IEventManager<DirectorEvent>.IEventArgs e) {
            if(e is EventArgs_PlaceOperate args) {
                // 先检查是不是角色 ID
                var role = RolesReader.GetRoleData(args.TargetID);
                if(role == null) {
                    ResolveEvent(args.TargetID);
                } else {
                    // todo 处理角色互动
                }
            }
        }

        private void OnConversationStepOn(IEventManager<DirectorEvent>.IEventArgs e) {
            if(e is EventArgs_ConversationStepOn args) {
                ResolveEvent(args.Event);
            }
        }

        private void OnChoiceStepOn(IEventManager<DirectorEvent>.IEventArgs e) {
            if(e is EventArgs_ChoiceStepOn args) {
                ResolveEvent(args.Event);
            }
        }
    }
}
